package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.pojo.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserService;
import com.heima.user.utils.AppJwtUtil;
import com.heima.user.utils.SendSms;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * <p>
 * APP用户信息表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Slf4j
@Service
@Transactional
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {

    private final RedisTemplate<Object, Object> redisTemplate;

    /**
     * 构造注入Bean
     *
     * @param redisTemplate redis
     */
    public ApUserServiceImpl(RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 用户登录
     *
     * @param dto 前端数据
     * @return 是否登录成功
     */
    @Override
    public ResponseResult login(LoginDto dto) {
        // 1.获取值
        String phone = dto.getPhone();
        String password = dto.getPassword();

        // 2.判断是否为游客登录
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(password)) {
            // 游客登录
            // 2.1使用0创建token，返回
            HashMap<String, Object> map = new HashMap<>();
            map.put("token", AppJwtUtil.getToken(0L));
            return ResponseResult.okResult(map);
        }

        // 3.判断用户是否存在
        // 3.1数据库查询用户
        ApUser user = this.getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, phone));
        // 3.2判断user是否存在
        if (user == null) {
            // 3.2.1用户不存在
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
        }

        // 4.判断密码是否正确
        // 4.1获取盐
        String salt = user.getSalt();
        // 4.2加密
        String encryptedPwd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
        // 4.3判断密码是否相等
        if (!encryptedPwd.equals(user.getPassword())) {
            // 4.3.1不相等
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
        }

        // 5.密码正确，设置返回对象
        HashMap<String, Object> map = new HashMap<>();
        // 5.1使用用户id创建token
        map.put("token", AppJwtUtil.getToken(user.getId().longValue()));
        // 5.2删除敏感信息并封装
        user.setPassword("");
        user.setSalt("");
        map.put("user", user);

        // 6.返回成功
        return ResponseResult.okResult(map);
    }

    /**
     * 获取验证码
     *
     * @param phone 手机号
     */
    @Override
    public ResponseResult getCode(String phone) {
        // 验证手机号是否符合要求
        if (!this.isValidPhoneNumber(phone)) {
            // 抛出参数非法异常
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 判断用户是否已注册
        // 数据库查询用户
        ApUser user = this.getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, phone));
        // 判断user是否存在
        if (user != null) {
            // 3.2.1用户存在
            throw new CustomException(AppHttpCodeEnum.DATA_EXIST);
        }
        // 生成随机验证码
        String code = (int) ((Math.random() * 9 + 1) * 100000) + "";
        // 发送短信
        SendSms.sendMsg(phone, code);
        // 存入Redis缓存中
        redisTemplate.opsForValue().set(phone, code, 1, TimeUnit.MINUTES);
        // 返回操作成功
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 验证码确认
     *
     * @param phone 手机号
     * @param code  验证码
     * @return 注册状态
     */
    @Override
    public ResponseResult verifyCode(String phone, String code) {
        // 从Redis缓存中获取信息
        String codeInRedis = (String) redisTemplate.opsForValue().get(phone);
        // 1.验证码判断
        if (StringUtils.isEmpty(codeInRedis)) {
            // 1.1验证码超时或手机号错误
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (!codeInRedis.equals(code)) {
            // 1.2验证码错误
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 响应成功，允许注册
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 用户注册
     *
     * @param user 用户基本信息
     * @return 状态
     */
    @Override
    public ResponseResult usrReg(ApUser user) {
        // 1.手机号校验
        String phone = user.getPhone();
        if (!this.isValidPhoneNumber(phone)) {
            // 抛出参数非法异常
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2.账户是否存在/冲突?
        String name = user.getName();
        if (StringUtils.isEmpty(name)) {
            // 账户不存在
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        // 3.获取密码加盐加密
        String password = user.getPassword();
        // 生成随机盐
        String salt = UUID.randomUUID().toString().replace("-", "");
        // MD5加密
        password = DigestUtils.md5DigestAsHex((password + salt).getBytes());

        // 4.补全字段
        user.setPassword(password);
        user.setSalt(salt);
        user.setCreatedTime(new Date());

        // 5.添加用户
        boolean saveBool = this.save(user);
        if (!saveBool) {
            // 添加失败
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }
        // 添加成功
        return ResponseResult.errorResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 手机号正则检验
     *
     * @param phoneNumber 手机号
     * @return bool
     */
    public boolean isValidPhoneNumber(String phoneNumber) {
        if ((phoneNumber != null) && (!phoneNumber.isEmpty())) {
            return Pattern.matches("^1[3-9]\\d{9}$", phoneNumber);
        }
        return false;
    }


}













